﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web;
using System.Web.Security;
using XQ.RequestOfficeSupplies.WebAPI.Filter;
using XQ.RequestOfficeSupplies.BLL.Account;
using XQ.RequestOfficeSupplies.DAL;
using XQ.RequestOfficeSupplies.DAL.Model.Sys;
using XQ.RequestOfficeSupplies.WebAPI.Models;
using System.Web.Http.Cors;
using XQ.RequestOfficeSupplies.WebAPI.Common;
using XQ.RequestOfficeSupplies.WebAPI.Common.WorkContext;
using System.Configuration;
using XQ.RequestOfficeSupplies.DAL.DAL.Common;
using XQ.RequestOfficeSupplies.DAL.DAL;
using XQ.RequestOfficeSupplies.DAL.Models;
using Newtonsoft.Json;
using XQ.RequestOfficeSupplies.BLL.Sys;
using XQ.RequestOfficeSupplies.DAL.Model.Business;
using XQ.RequestOfficeSupplies.DAL.Model;
using System.Net;
using System.Net.Http;
using System.Runtime.Caching; // 使用内存缓存
using System.Web.Http;
using System.Threading;
using System.Security.Cryptography;


namespace XQ.RequestOfficeSupplies.WebAPI.Controllers
{
    /// <summary>
    /// 账号相关
    /// </summary>
    public class AccountController : ApiController
    {
        UserBLL userBLL = new UserBLL();
        DepartmentBll departmentBll = new DepartmentBll();
        UserDal userDal = new UserDal();
        private readonly WebWorkContext X = null;

        private const int MAX_FAILED_ATTEMPTS = 8; // 最大失败次数
        private const int LOCKOUT_MINUTES = 15;    // 锁定时间（分钟）
        private const int DELAY_SECONDS = 2;       // 失败后延迟响应（秒）
        private const int IP_MAX_ATTEMPTS = 10;    // 同IP最大尝试次数

        // 缓存键名前缀
        private const string ACCOUNT_PREFIX = "RequestOfficeSuppliesLoginAttempt_Account_";
        private const string IP_PREFIX = "RequestOfficeSuppliesLoginAttempt_IP_";

        public AccountController()
        {
            this.X = new WebWorkContext(HttpContext.Current);
        }
        /// <summary>
        /// 登录接口
        /// </summary>
        /// <param name="loginModel">用户名 密码</param>
        /// <returns></returns>
        [Route("Api/Account/Login")]
        public ResultModel Login(LoginModel loginModel)
        {
            ResultModel resultModel = new ResultModel();
            UserInfoResult userInfoResult = new UserInfoResult();
            try
            {
                // 获取客户端IP
                string clientIp = GetClientIp();

                // 1. 检查IP限制
                if (clientIp != "0.0.0.0" && IsIpBlocked(clientIp))
                {
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "Too many requests. Try again after 10 minutes";

                    return resultModel;
                }

                // 2. 检查账户锁定状态
                if (IsAccountLocked(loginModel.UserName))
                {
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "账号已锁定，请在15分钟后再试！";

                    return resultModel;
                }

                // 3. 验证用户凭证（示例）
                Sys_Users user = LoginBll.Instance.GetLoginResult(loginModel.UserName, loginModel.Password);

                if (user == null)
                {
                    // 增加失败计数
                    IncrementFailedAttempt(loginModel.UserName, clientIp);

                    // 延迟响应增加攻击成本
                    Thread.Sleep(DELAY_SECONDS * 1000);
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "用户名或密码不正确，连续错误5次以上账号将会被锁定！";

                    return resultModel;
                }

                // 4. 登录成功：重置计数器
                ResetFailedAttempts(loginModel.UserName);
                ResetIpAttempts(clientIp);
                
                if (user != null)
                {
                    LogBll.Instance.WriteLog(LogBll.LogType.LogIn, "", user.id, "用户登录", "", "", "", user.TrueName);
                    resultModel.success = true;
                    
                    //账号禁用
                    if (user.IsDisabled == true)
                    {
                        resultModel.code = "10001";
                        resultModel.message = "帐号已被禁用！";
                        return resultModel;
                    }
                    this.X.SetUserLogin(user, false);
                    userInfoResult.User = user;
                    userInfoResult.RoleID = new RoleBll().GetRoleIDByUserID(user.id);
                    userInfoResult.Token = TokenHelper.CreateToken(user.id, user.DepartmentID, userInfoResult.RoleID, "");
                    Sys_Departments department = departmentBll.GetDepById((int)user.DepartmentID);
                    userInfoResult.DepartmentID = department.Id;
                    userInfoResult.DepartmentCode = department.Code;
                    userInfoResult.DepartmentCodePrefix = department.depth == 3 ? department.Code.Substring(0, 2) : department.Code;
                    userInfoResult.DepartmentDepth = (int)department.depth;
                    userInfoResult.DepartmentName = department.DepartmentName;
                    userInfoResult.IsSpecial = department.Remark == "OtherDepartment";


                    resultModel.code = "10000";
                    resultModel.message = "调用成功";
                    resultModel.data = userInfoResult;
                    return resultModel;
                }
                else
                {
                    resultModel.code = "10002";
                    resultModel.message = "登录失败，无效的用户名或密码";
                    return resultModel;
                }
            }
            catch (Exception ex)
            {
                resultModel.success = false;
                resultModel.code = "10001";
                resultModel.message = "执行失败";
                resultModel.data = ex.Message;

                return resultModel;
            }

        }

        #region 防暴破机制
        private bool IsAccountLocked(string username)
        {
            var cache = MemoryCache.Default;
            string key = ACCOUNT_PREFIX + username;
            return cache.Get(key) as int? >= MAX_FAILED_ATTEMPTS;
        }

        private bool IsIpBlocked(string ip)
        {
            var cache = MemoryCache.Default;
            string key = IP_PREFIX + ip;
            return cache.Get(key) as int? >= IP_MAX_ATTEMPTS;
        }

        private void IncrementFailedAttempt1(string key, string prefix)
        {
            var cache = MemoryCache.Default;
            string cacheKey = prefix + key;

            int attempts = 1;
            if (cache.Contains(cacheKey))
            {
                attempts = (int)cache.Get(cacheKey) + 1;
            }

            // 设置带过期时间的缓存
            cache.Set(cacheKey, attempts, DateTimeOffset.Now.AddMinutes(LOCKOUT_MINUTES));
        }

        private void IncrementFailedAttempt(string username, string ip)
        {
            IncrementFailedAttempt1(username, ACCOUNT_PREFIX);
            IncrementFailedAttempt1(ip, IP_PREFIX);
        }

        private void ResetFailedAttempts(string key, string prefix)
        {
            MemoryCache.Default.Remove(prefix + key);
        }

        private void ResetFailedAttempts(string username)
        {
            ResetFailedAttempts(username, ACCOUNT_PREFIX);
        }

        private void ResetIpAttempts(string ip)
        {
            ResetFailedAttempts(ip, IP_PREFIX);
        }
        #endregion

        #region 辅助方法
        private string GetClientIp()
        {
            // 优先从X-Forwarded-For头获取（适用于代理/负载均衡环境）
            if (Request.Headers.Contains("X-Forwarded-For"))
            {
                string xForwardedFor = Request.Headers.GetValues("X-Forwarded-For").FirstOrDefault();
                if (!string.IsNullOrEmpty(xForwardedFor))
                {
                    // 可能有多个IP，取第一个
                    string[] ips = xForwardedFor.Split(',');
                    return ips[0].Trim();
                }
            }

            // 从HttpContext获取（适用于IIS托管）
            if (HttpContext.Current != null &&
                HttpContext.Current.Request != null)
            {
                return HttpContext.Current.Request.UserHostAddress;
            }

            // 从Owin环境获取（如果可用）
            if (Request.Properties.ContainsKey("MS_HttpContext"))
            {
                return ((HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.UserHostAddress;
            }

            // 最后回退到远程端点
            if (Request.Properties.ContainsKey("System.ServiceModel.Channels.RemoteEndpointMessageProperty"))
            {
                dynamic remoteEndpoint = Request.Properties["System.ServiceModel.Channels.RemoteEndpointMessageProperty"];
                return remoteEndpoint.Address;
            }

            return "0.0.0.0";
        }

        #endregion

        /// <summary>
        /// 绑定账号对应的openid
        /// </summary>
        /// <param name="loginModel"></param>
        /// <returns></returns>
        [Route("Api/Account/BindOpenid")]
        public ResultModel BindOpenid(LoginModel loginModel)
        {
            ResultModel resultModel = new ResultModel();
            UserInfoResult userInfoResult = new UserInfoResult();
            try
            {
                // 获取客户端IP
                string clientIp = GetClientIp();

                // 1. 检查IP限制
                if (clientIp != "0.0.0.0" && IsIpBlocked(clientIp))
                {
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "Too many requests. Try again after 10 minutes";

                    return resultModel;
                }

                // 2. 检查账户锁定状态
                if (IsAccountLocked(loginModel.UserName))
                {
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "账号已锁定，请在15分钟后再试！";

                    return resultModel;
                }

                // 3. 验证用户凭证（示例）
                Sys_Users user = LoginBll.Instance.GetLoginResult(loginModel.UserName, loginModel.Password);

                if (user == null)
                {
                    // 增加失败计数
                    IncrementFailedAttempt(loginModel.UserName, clientIp);

                    // 延迟响应增加攻击成本
                    Thread.Sleep(DELAY_SECONDS * 1000);
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "用户名或密码不正确，连续错误5次以上账号将会被锁定！";

                    return resultModel;
                }

                // 4. 登录成功：重置计数器
                ResetFailedAttempts(loginModel.UserName);
                ResetIpAttempts(clientIp);
                //Sys_Users user = LoginBll.Instance.GetLoginResult(loginModel.UserName, loginModel.Password);
                if (user != null)
                {
                    LogBll.Instance.WriteLog(LogBll.LogType.LogIn, "", user.id, "绑定账号对应的openid，验证登录", "", "", "", user.TrueName);

                    //暂没有验证此账号是否绑定过微信openid,有新绑定时直接替换原来的绑定
                    user.openid = loginModel.Openid;
                    userDal.UpdateModel(user);


                    resultModel.success = true;

                    //账号禁用
                    if (user.IsDisabled == true)
                    {
                        resultModel.code = "10001";
                        resultModel.message = "帐号已被禁用！";
                        return resultModel;
                    }
                    userInfoResult.User = user;
                    userInfoResult.RoleID = new RoleBll().GetRoleIDByUserID(user.id);
                    userInfoResult.Token = TokenHelper.CreateToken(user.id, user.DepartmentID, userInfoResult.RoleID, "");

                    resultModel.code = "10000";
                    resultModel.message = "调用成功";
                    resultModel.data = userInfoResult;
                    return resultModel;
                }
                else
                {
                    resultModel.code = "10002";
                    resultModel.message = "绑定失败，无效的用户名或密码";
                    return resultModel;
                }
            }
            catch (Exception ex)
            {
                resultModel.success = false;
                resultModel.code = "10001";
                resultModel.message = "执行失败";
                resultModel.data = ex.Message;

                return resultModel;
            }
        }

        /// <summary>
        /// 解绑账号对应的openid
        /// </summary>
        /// <returns></returns>
        [Route("Api/Account/UnBindOpenid")]
        [HttpGet]
        public ResultModel UnBindOpenid()
        {
            ResultModel resultModel = new ResultModel();
            
            try
            {
                TokenModel token = TokenHelper.GetTokenByHeaders(Request.Headers);
                if (token != null && token.UID > 0)
                {
                    Sys_Users user = userDal.FindModel(u => u.id == token.UID);
                    user.openid = "";
                    resultModel.data = userDal.UpdateModel(user) == 1;
                    resultModel.success = true;
                    resultModel.code = "10000";
                    resultModel.message = "调用成功";

                }
                else {
                    resultModel.success = false;
                    resultModel.code = "10001";
                    resultModel.message = "Token解析失败！";
                }
                return resultModel;
            }
            catch (Exception ex)
            {
                resultModel.success = false;
                resultModel.code = "10001";
                resultModel.message = "执行失败";
                resultModel.data = ex.Message;

                return resultModel;
            }
        }

        /// <summary>
        /// 建设单位绑定工程的openid
        /// </summary>
        /// <param name="loginModel"></param>
        /// <returns></returns>
        [Route("Api/Account/JSDWBindOpenid")]
        public ResultModel JSDWBindOpenid(LoginModel loginModel)
        {
            ResultModel resultModel = new ResultModel();
            resultModel.success = false;
            resultModel.code = "10001";
            resultModel.message = "执行失败";
            resultModel.data = "手机号或验证码不正确";

            try
            {
                if (loginModel != null && loginModel.UserName != null && loginModel.UserName.Length == 11 && loginModel.Password != null && loginModel.Password.Length == 6)
                {
                    //验证手机号与验证码
                    if (loginModel.UserName.Substring(9, 1) == loginModel.Password.Substring(1, 1)
                        && loginModel.UserName.Substring(6, 1) == loginModel.Password.Substring(3, 1)
                        && loginModel.UserName.Substring(2, 1) == loginModel.Password.Substring(5, 1))
                    {
                        resultModel.success = true;
                        resultModel.code = "10000";
                        resultModel.message = "绑定成功";
                        resultModel.data = true;
                        return resultModel;
                    }

                    
                }
                LogBll.Instance.WriteLog(LogBll.LogType.Other, "", 0, "建设单位绑定工程的openid", "", "", "", "Api/Account/JSDWBindOpenid：" + JsonConvert.SerializeObject(loginModel));
                return resultModel;
            }
            catch (Exception ex)
            {
                LogBll.Instance.WriteErrLog("", 0, "建设单位绑定工程的openid报错", "", "", JsonConvert.SerializeObject(loginModel), ex.Message, "", "ProjectController", "SaveProject");
                resultModel.success = false;
                resultModel.code = "10001";
                resultModel.message = "执行失败";
                resultModel.data = ex.Message;

                return resultModel;
            }
        }


        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [Route("Api/Account/UpdatePassword")]
        [HttpPost]
        public ResultModel UpdatePassword([FromBody] UpdatePasswordModel model)
        {
            ResultModel resultModel = new ResultModel();
            resultModel.success = false;
            resultModel.code = "10001";
            resultModel.message = "执行失败";
            resultModel.data = "原密码不正确";

            TokenModel token = TokenHelper.GetTokenByHeaders(Request.Headers);
            try
            {
                if(token ==null || token.UID==0)
                {
                    resultModel.data = "没有获取到Token信息";
                    return resultModel;
                }
                model.UserID = token.UID;
                Sys_Users user = LoginBll.Instance.GetUserByIDAndPassword(model.UserID, model.OldPassword);
                if (user != null)
                {
                    UserBLL bll = new UserBLL();
                    user.Password = model.NewPassword;                    
                    resultModel.data = bll.SaveUser(user) == 1;
                    resultModel.success = true;
                    resultModel.code = "10000";
                    resultModel.message = "执行成功";
                }
                LogBll.Instance.WriteLog(LogBll.LogType.Other, "", 0, "修改密码", "", "", "", "Api/Account/UpdatePassword：" + JsonConvert.SerializeObject(model) + JsonConvert.SerializeObject(token));
                return resultModel;
            }
            catch (Exception ex)
            {
                LogBll.Instance.WriteErrLog("", 0, "修改密码报错", "", "", JsonConvert.SerializeObject(model) + JsonConvert.SerializeObject(token), ex.Message, "", "AccountController", "UpdatePassword");
                resultModel.success = false;
                resultModel.code = "10001";
                resultModel.message = "执行失败";
                resultModel.data = ex.Message;

                return resultModel;
            }
        }
    }
}